package com.ruoyi.learn.java.design.pattern.struct;

/**
 * 代理模式 (Proxy Pattern) 示例：实现文档的延迟加载和权限控制。
 */
/**
 * 代理模式 (Proxy Pattern) 示例：实现文档的延迟加载和权限控制。
 */
public class ProxyPatternDemo {

    //region ========== 1. 抽象主题 (Subject Interface) ==========

    /**
     * 抽象主题：文档
     * 定义了真实文档和代理文档共同的接口。
     */
    public interface Document {
        void display(); // 显示文档内容
        String getTitle(); // 获取文档标题
    }

    //endregion

    //region ========== 2. 真实主题 (Real Subject) ==========

    /**
     * 真实主题：真实文档
     * 实际执行业务逻辑的类，加载可能很耗时。
     */
    public static class RealDocument implements Document {
        private String title;
        private String content;

        public RealDocument(String title) {
            this.title = title;
            loadFromDisk(); // 模拟耗时的加载操作
        }

        /**
         * 模拟从磁盘加载文档内容（耗时操作）
         */
        private void loadFromDisk() {
            System.out.println("    > 正在从磁盘加载文档 '" + title + "' 的内容... (耗时操作)");
            try {
                Thread.sleep(1500); // 模拟延迟
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            this.content = "这是文档 '" + title + "' 的详细内容。";
            System.out.println("    > 文档 '" + title + "' 加载完成。");
        }

        @Override
        public void display() {
            System.out.println("【文档内容】" + content);
        }

        @Override
        public String getTitle() {
            return title;
        }
    }

    //endregion

    //region ========== 3. 代理 (Proxy) ==========

    /**
     * 代理：文档代理
     * 实现 Document 接口，持有 RealDocument 的引用（延迟初始化），
     * 并在访问前进行权限检查。
     */
    public static class DocumentProxy implements Document {
        private String title;
        private RealDocument realDocument; // 延迟加载，初始为 null
        private String currentUser; // 当前用户，用于权限检查

        public DocumentProxy(String title, String currentUser) {
            this.title = title;
            this.currentUser = currentUser;
            System.out.println("    > 创建了 '" + title + "' 的代理对象。真实文档尚未加载。");
        }

        /**
         * 检查当前用户是否有权限访问此文档。
         * 这里简单模拟：只有用户名包含 "admin" 才能访问。
         * @return 是否有权限
         */
        private boolean checkAccess() {
            boolean hasAccess = currentUser != null && currentUser.contains("admin");
            System.out.println("    > 权限检查：用户 '" + currentUser + "' " + (hasAccess ? "有" : "无") + "权访问文档 '" + title + "'");
            return hasAccess;
        }

        /**
         * 延迟加载真实文档。
         * 只有在需要时才创建 RealDocument 实例。
         */
        private void loadRealDocument() {
            if (realDocument == null) {
                System.out.println("    > 代理：开始加载真实文档 '" + title + "'...");
                realDocument = new RealDocument(title);
                System.out.println("    > 代理：真实文档 '" + title + "' 加载完毕。");
            }
        }

        //region ========== 实现 Subject 接口 ==========

        @Override
        public void display() {
            System.out.println("【代理】收到 display() 请求。");
            if (checkAccess()) {
                System.out.println("【代理】权限通过，准备显示内容...");
                loadRealDocument(); // 确保真实文档已加载
                realDocument.display(); // 转发请求给真实对象
                System.out.println("【代理】内容显示完成。");
            } else {
                System.out.println("【代理】权限不足，无法显示文档内容。");
            }
        }

        @Override
        public String getTitle() {
            // 获取标题通常不需要权限，也不需要加载完整内容
            return title;
        }

        //endregion
    }

    //endregion

    //region ========== 4. 客户端 (Client) ==========

    /**
     * 文档查看器客户端
     * 它只知道 Document 接口，不关心是真实文档还是代理。
     */
    public static class DocumentViewer {
        public void viewDocument(Document document) {
            System.out.println("【客户端】正在查看文档: '" + document.getTitle() + "'");
            document.display(); // 无论 document 是 RealDocument 还是 DocumentProxy，调用方式相同
            System.out.println("---");
        }
    }

    //endregion

    //region ========== 5. 主函数 (Main) - 演示代理模式 ==========

    public static void main(String[] args) {
        System.out.println("=== 代理模式演示 ===\n");
        DocumentViewer viewer = new DocumentViewer();

        // 1. 用户 "alice" (非管理员) 尝试访问文档
        System.out.println("1. 用户 'alice' 尝试访问 '项目计划书'");
        Document doc1 = new DocumentProxy("项目计划书", "alice");
        viewer.viewDocument(doc1);

        // 2. 用户 "bob_admin" (管理员) 尝试访问同一文档
        // 注意：这里创建了一个新的代理实例，但指向同一个逻辑文档
        System.out.println("2. 用户 'bob_admin' 尝试访问 '项目计划书'");
        Document doc2 = new DocumentProxy("项目计划书", "bob_admin");
        viewer.viewDocument(doc2);

        // 3. 用户 "charlie_admin" 尝试访问另一个文档
        System.out.println("3. 用户 'charlie_admin' 尝试访问 '机密报告'");
        Document doc3 = new DocumentProxy("机密报告", "charlie_admin");
        viewer.viewDocument(doc3);

        // 4. 演示直接使用真实对象（对比）
        System.out.println("4. 直接使用真实文档 (无代理)");
        Document directDoc = new RealDocument("直接加载的文档");
        viewer.viewDocument(directDoc);
    }

    //endregion
}